package main

/*
#include <stdlib.h>
extern int text_to_speech(const char* src_text, const char* des_path);
*/
import "C"

import (
	"bufio"
	"bytes"
	"encoding/binary"
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"path/filepath"
	"strings"
	"unsafe"
)

func newWavFile(fn string) *os.File {
	fp, err := os.Create(fn)
	if err != nil {
		panic(err)
	}
	hdr := createWavHeader()
	fp.Write(hdr)
	return fp
}

var hdrSize int32

func endWaveFile(fp *os.File, dataSize int32) {
	var sizeD8 int32 = dataSize + hdrSize - 8
	var buf [4]byte
	binary.LittleEndian.PutUint32(buf[:], uint32(sizeD8))
	fp.Seek(4, 0)
	fp.Write(buf[:])

	binary.LittleEndian.PutUint32(buf[:], uint32(dataSize))
	fp.Seek(40, 0)
	fp.Write(buf[:])
}

func textToPcm(s string) []byte {
	s = strings.TrimSpace(s)
	if s == "" {
		return nil
	}

	t := C.CString(s)
	defer C.free(unsafe.Pointer(t))

	fp1 := filepath.Join(os.TempDir(), fmt.Sprintf("out%05d.wav", file_num))
	file_num++
	if C.text_to_speech(t, C.CString(fp1)) != 0 {
		panic("text to speech fail.")
	}
	data, err := ioutil.ReadFile(fp1)
	if err != nil {
		panic(err)
	}

	return data[44:]
}

func fileToWav(fnIn, fnOut string, v int) {
	var dataSize int32 = 0

	var fp io.Reader
	if fnIn == "" {
		fp = os.Stdin
	} else {
		fp1, err := os.Open(fnIn)
		if err != nil {
			panic(err)
		}
		defer fp1.Close()
		fp = fp1
	}

	fpOut := newWavFile(fnOut)
	defer fpOut.Close()
	initMSC()
	reader := bufio.NewReader(fp)
	//regex1 := regexp.MustCompile("\\s+")
	for {
		var pcm []byte
		line1, err := reader.ReadString('\n')
		if err != nil {
			//log.Println(err)
			break
		}

		if len(line1) == 0 {
			continue
		}

		line1 = strings.TrimSpace(line1)

		runes1 := bytes.Runes([]byte(line1))

		//fmt.Println(string(runes1))

		if len(runes1) < 60 {
			pcm = textToPcm(string(runes1))
			if pcm == nil {
				continue
			}
			fpOut.Write(pcm)
			dataSize += int32(len(pcm))
			continue
		}
		for {
			pos := getBreakPos(runes1)
			if len(runes1)-pos < 8 {
				pos = len(runes1)
			}
			if pos > 0 {
				pcm = textToPcm(string(runes1[0:pos]))
				fpOut.Write(pcm)
				dataSize += int32(len(pcm))
			}
			if len(runes1) > pos {
				runes1 = runes1[pos:]
			} else {
				break
			}
		}
	}
	endWaveFile(fpOut, dataSize)
}

/*
{
	char            riff[4];                // = "RIFF"
	int				size_8;                 // = FileSize - 8
	char            wave[4];                // = "WAVE"
	char            fmt[4];                 // = "fmt "
	int				fmt_size;				// = 下一个结构体的大小 : 16

	short int       format_tag;             // = PCM : 1
	short int       channels;               // = 通道数 : 1
	int				samples_per_sec;        // = 采样率 : 16000
	int				avg_bytes_per_sec;      // = 每秒字节数 : 32000
	short int       block_align;            // = 每采样点字节数 : 2
	short int       bits_per_sample;        // = 量化比特数: 16

	char            data[4];                // = "data";
	int				data_size;              // = 纯数据长度 : FileSize - 44
}
*/

func createWavHeader() []byte {
	hdr := bytes.NewBufferString("RIFF")
	//int size-8  = FileSize - 8
	hdr.Write([]byte{0, 0, 0, 0})
	//wave = "WAVE"
	//fmt = "fmt "
	hdr.WriteString("WAVEfmt ")
	//int fmt_size = 16
	hdr.Write(bytesInt32(16))
	//short int format_tag = 1
	hdr.Write(bytesInt16(1))
	//short int       channels=1
	hdr.Write(bytesInt16(1))
	//int				samples_per_sec==16000
	hdr.Write(bytesInt32(16000))
	//int				avg_bytes_per_sec=32000
	hdr.Write(bytesInt32(32000))
	//short int       block_align=2
	hdr.Write(bytesInt16(2))
	//short int       bits_per_sample=16
	hdr.Write(bytesInt16(16))
	//data = "data"
	hdr.WriteString("data")
	//int				data_size = FileSize - 44
	hdr.Write([]byte{0, 0, 0, 0})
	hdrSize = int32(hdr.Len())
	return hdr.Bytes()
}

func bytesInt32(v int32) []byte {
	var buf [4]byte
	binary.LittleEndian.PutUint32(buf[:], uint32(v))
	return buf[:]
}

func bytesInt16(v int16) []byte {
	var buf [2]byte
	binary.LittleEndian.PutUint16(buf[:], uint16(v))
	return buf[:]
}
